﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace PSE.Framework.UI.Controls.SmartClient
{
    public class ChangesMonitorContainer : ContentControl, IChangesMonitorContainer, IWeakEventListener
    {
        #region propriedades

        /// <summary>
        /// Indica se o objeto teve alterações
        /// </summary>
        /// <value></value>
        public bool HasChanges
        {
            get { return (bool)GetValue(HasChangesProperty); }
            protected internal set { SetValue(HasChangesKey, value); }
        }

        // Using a DependencyProperty as the backing store for HasChanges.  This enables animation, styling, binding, etc...
        protected internal static readonly DependencyPropertyKey HasChangesKey =
            DependencyProperty.RegisterReadOnly("HasChanges", typeof(bool), typeof(ChangesMonitorContainer), new FrameworkPropertyMetadata(false));

        public static readonly DependencyProperty HasChangesProperty = HasChangesKey.DependencyProperty;
        
        #endregion


        /// <summary>
        /// Initializes a new instance of the <see cref="ChangesMonitorContainer"/> class.
        /// </summary>
        public ChangesMonitorContainer()
        {
            AddChangedHandler();
            this.Loaded += new RoutedEventHandler(ChangesControl_Loaded);
            this.ChangesCleaned += new RoutedEventHandler(ChangesMonitorContainer_ChangesCleaned);       
        }

        protected virtual void AddChangedHandler()
        {
            ChangesMonitorManager.AddChangesHandler(this, new RoutedEventHandler(ControlHasChangedHandler));
        }

        protected void ControlHasChangedHandler(object sender, RoutedEventArgs e)
        {
            this.ControlHasChanged((DependencyObject)e.Source);

            // Se estiver desabilitado não sobe o evento
            if (!this.IsMonitoringChanges)
            {
                e.Handled = true;
            }
        }

        internal void ControlHasChanged(DependencyObject element)
        {
            if (this.IsMonitoringChanges)
            {
                RoutedEventArgs changesEventArgs = new RoutedEventArgs(HasChangedEvent, element);
                this.RaiseEvent(changesEventArgs);
                HasChanges = true;
            }
        }

        /// <summary>
        /// Handles the ChangesCleaned event of the ChangesMonitorContainer control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        void ChangesMonitorContainer_ChangesCleaned(object sender, RoutedEventArgs e)
        {
            if (this.HasChanges)
            {
                CheckChangesEventArgs checkChangesEventArgs = new CheckChangesEventArgs(CheckChangesEvent, this);
                this.RaiseEvent(checkChangesEventArgs);
                this.HasChanges = checkChangesEventArgs.HasChanges;
            }
        }

        /// <summary>
        /// Handles the Loaded event of the ChangesControl control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        void ChangesControl_Loaded(object sender, RoutedEventArgs e)
        {
            IChangesMonitorContainer container = (IChangesMonitorContainer)ControlHelper.FindParent(this, typeof(IChangesMonitorContainer));
            if (container != null)
            {
                //container.CleaningChanges += new RoutedEventHandler(container_CleaningChanges);
                CleaningChangesEventManager.AddListener(container, this);

                //container.CheckChanges += new EventHandler<CheckChangesEventArgs>(container_CheckChanges);
                CheckChangesEventManager.AddListener(container, this);
            }
        }

        /// <summary>
        /// Handles the CheckChanges event of the container control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="PSE.Framework.UI.Controls.SmartClient.CheckChangesEventArgs"/> instance containing the event data.</param>
        void container_CheckChanges(object sender, CheckChangesEventArgs e)
        {
            if (this.HasChanges) e.HasChanges = true;
        }

        /// <summary>
        /// Handles the CleaningChanges event of the container control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        void container_CleaningChanges(object sender, RoutedEventArgs e)
        {
            ClearChanges();
        }

        ///// <summary>
        ///// DEPRECATED
        ///// Handles the SourceUpdated event of the ChangesControl control.
        ///// </summary>
        ///// <param name="sender">The source of the event.</param>
        ///// <param name="e">The <see cref="System.Windows.Data.DataTransferEventArgs"/> instance containing the event data.</param>
        //void ChangesControl_SourceUpdated(object sender, System.Windows.Data.DataTransferEventArgs e)
        //{
        //    RoutedEventArgs changesEventArgs = new RoutedEventArgs(HasChangedEvent,e.Source);
        //    this.RaiseEvent(changesEventArgs);
        //    HasChanges = true;
        //}

        #region HasChanged

        public static RoutedEvent HasChangedEvent = EventManager.RegisterRoutedEvent("HasChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ChangesMonitorContainer));
        /// <summary>
        /// Occurs when [has changed].
        /// </summary>
        public event RoutedEventHandler HasChanged
        {
            add { AddHandler(HasChangedEvent, value); }
            remove { RemoveHandler(HasChangedEvent, value); }
        }

        #endregion

        #region CleaningChanges

        public static RoutedEvent CleaningChangesEvent = EventManager.RegisterRoutedEvent("CleaningChanges", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(ChangesMonitorContainer));
        /// <summary>
        /// Occurs when [cleaning changes].
        /// </summary>
        public event RoutedEventHandler CleaningChanges
        {
            add { AddHandler(CleaningChangesEvent, value); }
            remove { RemoveHandler(CleaningChangesEvent, value); }
        }

        #endregion

        #region ClearChanges

        /// <summary>
        /// Clears the changes.
        /// </summary>
        public void ClearChanges()
        {
            if (HasChanges)
            {
                HasChanges = false;
                RoutedEventArgs cleaningChangesEventArgs = new RoutedEventArgs(CleaningChangesEvent, this);
                RaiseEvent(cleaningChangesEventArgs);

                RoutedEventArgs changesCleanedEventArgs = new RoutedEventArgs(ChangesCleanedEvent, this);
                RaiseEvent(changesCleanedEventArgs);
            }
        }

        #endregion


        public static readonly DependencyProperty IsMonitoringChangesProperty = DependencyProperty.Register("IsMonitoringChanges", typeof(bool), typeof(ChangesMonitorContainer), new FrameworkPropertyMetadata(true, OnIsMonitoringChangesChanged));

        public bool IsMonitoringChanges
        {
            get { return (bool)GetValue(IsMonitoringChangesProperty); }
            set { SetValue(IsMonitoringChangesProperty, value); }
        }

        private static void OnIsMonitoringChangesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ChangesMonitorContainer monitor = (ChangesMonitorContainer)d;
            monitor.ClearChanges();
        }

        #region IChangesMonitorContainer Members

        public static RoutedEvent ChangesCleanedEvent = EventManager.RegisterRoutedEvent("ChangesCleaned", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(ChangesMonitorContainer));
        /// <summary>
        /// Occurs when [changes cleaned].
        /// </summary>
        public event RoutedEventHandler ChangesCleaned
        {
            add { AddHandler(ChangesCleanedEvent, value); }
            remove { RemoveHandler(ChangesCleanedEvent, value); }
        }

        public static RoutedEvent CheckChangesEvent = EventManager.RegisterRoutedEvent("CheckChanges", RoutingStrategy.Direct, typeof(EventHandler<CheckChangesEventArgs>), typeof(ChangesMonitorContainer));

        /// <summary>
        /// Occurs when [check changes].
        /// </summary>
        public event EventHandler<CheckChangesEventArgs> CheckChanges
        {
            add { AddHandler(CheckChangesEvent, value); }
            remove { RemoveHandler(CheckChangesEvent, value); }
        }

        #endregion

        #region ReceiveWeakEvent
        public virtual bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
        {
            if (managerType == typeof(CleaningChangesEventManager))
            {
                container_CleaningChanges(sender, (RoutedEventArgs)e);
            }
            else if (managerType == typeof(CheckChangesEventManager))
            {
                container_CheckChanges(sender, (CheckChangesEventArgs)e);
            }
            else
            {
                return false;
            }
            return true;
        }
        #endregion
    }
}
